// WorkerThreadManager.cpp
//
#include "WorkerThreadManager.h"

#include <QThreadPool>
#include "WorkerThread.h"
#include "VObjectGL.h"

#include "TimedBlock.h"
#include "MemCheck.h"

using namespace IDS;
using namespace IDS::IDEAS::OpenGLView;


// --------------------------------------------------------------------------------------------
WorkerThreadManager::WorkerThreadManager()
: QThread(),
  MAX_WORKER_THREAD_NUMBER(4),
  updating(false),
  running(false)
{
	for(int i=0; i<MAX_WORKER_THREAD_NUMBER; ++i)
		threadPool.push_back( new WorkerThread );
}

// --------------------------------------------------------------------------------------------
WorkerThreadManager::~WorkerThreadManager()
{
	for(int i=0; i<MAX_WORKER_THREAD_NUMBER; ++i)
		delete threadPool[i];

	threadPool.clear();

	mutex.lock();
	updateQueue.clear();
	removeQueue.clear();
	mutex.unlock();
	
	deletePendingObjects();
}

// --------------------------------------------------------------------------------------------
void WorkerThreadManager::start()
{
	running = true;
	QThread::start();
}

// --------------------------------------------------------------------------------------------
void WorkerThreadManager::stop()
{
	running = false;
	QThread::quit();
}

// --------------------------------------------------------------------------------------------
void WorkerThreadManager::addTask( const Task &task )
{
	mutex.lock();

	switch( task.operation )
	{
	case WorkerThreadManager::UPDATE_OBJECT:
		updateQueue.clear();
		for(size_t i=0; i<task.objects.size(); ++i)
		{
			Request r;
			r.object    = task.objects[i];
			r.precision = task.precision;
		
			updateQueue.enqueue(r);
		}
		break;

	case WorkerThreadManager::DELETE_OBJECT:
		for(size_t i=0; i<task.objects.size(); ++i)
		{
			Request r;
			r.object    = task.objects[i];
			r.precision = task.precision;
		
			removeQueue.enqueue(r);
		}
		break;	
	}


	mutex.unlock();
}

// --------------------------------------------------------------------------------------------
void WorkerThreadManager::removeDeletedObjects()
{
	mutex.lock();
	while( !removeQueue.isEmpty() )
	{
		Request r = removeQueue.dequeue();
		for( QQueue<Request>::iterator it = updateQueue.begin(); it!=updateQueue.end(); )
		{
			if( it->object == r.object )
				it = updateQueue.erase(it);
			else
				++it;
		}
		pending.push_back( r.object );
	}
	mutex.unlock();
}

// --------------------------------------------------------------------------------------------
void WorkerThreadManager::deletePendingObjects()
{
	mutex.lock();
	for( QList<VObjectGL*>::iterator it = pending.begin(); it!=pending.end(); ++it )
		delete *it;

	pending.clear();
	mutex.unlock();
}

// --------------------------------------------------------------------------------------------
int WorkerThreadManager::getFreeWorker()
{
	int freeIndex = -1;
	for(int i=0; i<MAX_WORKER_THREAD_NUMBER; ++i)
	{
		if( !threadPool[i]->isRunning() )
		{
			freeIndex = i;
			break;
		}	
	}

	return freeIndex;
}

// --------------------------------------------------------------------------------------------
int WorkerThreadManager::getBusyWorker()
{
	int busyIndex = -1;
	for(int i=0; i<MAX_WORKER_THREAD_NUMBER; ++i)
	{
		if( threadPool[i]->isRunning() )
		{
			busyIndex = i;
			break;
		}	
	}

	return busyIndex;
}

// --------------------------------------------------------------------------------------------
bool WorkerThreadManager::scheduleTask()
{
	bool scheduled = false;
	mutex.lock();
	if( !updateQueue.isEmpty() )
	{
		int freeWorker = getFreeWorker();
		if(  freeWorker < 0 )
		{
			scheduled = false;
			mutex.unlock();
		}
		else
		{
			Request t = updateQueue.dequeue();
			mutex.unlock();

			threadPool[freeWorker]->setTask( t.object, t.precision );
			QThreadPool::globalInstance()->start( threadPool[freeWorker] );
			updating  = true;
			scheduled = true;

			//mutex.lock();
			//updateQueue.();
			//mutex.unlock();
		}
	}
	else
	{
		mutex.unlock();
	}

	return scheduled;
}

// --------------------------------------------------------------------------------------------
void WorkerThreadManager::run()
{
	while(running)
	{
		removeDeletedObjects();

		bool scheduled = scheduleTask();
		
		usleep(1000);

		if( !pending.empty() && getBusyWorker() < 0 )
			deletePendingObjects();			
	}
}